home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 408_01 / article.c < prev    next >
C/C++ Source or Header  |  1993-08-06  |  32KB  |  1,157 lines

  1. /*
  2.     SNEWS 1.91
  3.  
  4.     article - routines to read and display an article
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.                         PO Box 2708, Christchurch, NEW ZEALAND
  10.  
  11.     Modifications copyright (C) 1993  Daniel Fandrich
  12.                         <dan@fch.wimsey.bc.ca> or CompuServe 72365,306
  13.  
  14.     This program is free software; you can redistribute it and/or modify
  15.     it under the terms of the GNU General Public License, version 1, as
  16.     published by the Free Software Foundation.
  17.  
  18.     This program is distributed in the hope that it will be useful,
  19.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.     GNU General Public License for more details.
  22.  
  23.     See the file COPYING, which contains a copy of the GNU General
  24.     Public License.
  25.  
  26.  
  27.     Source is formatted with a tab size of 4.
  28.  
  29.  */
  30.  
  31.  
  32. #include "defs.h"
  33. #include "snews.h"
  34. #include "pccharst.h"
  35. #include <alloc.h>
  36. #include <dir.h>
  37. #include <io.h>
  38. #include <ctype.h>
  39.  
  40. enum char_sets current_char_set = DEFAULT_CHAR_SET;
  41. int active_code_page;
  42.  
  43. static char *empty_line = "\n";        /* static empty line structure */
  44.  
  45. void ReplyAddress(TEXT *tx, char *subject);
  46.  
  47.  
  48. /*-------------------- set up the global code page vars --------------------*/
  49. void select_code_page(void)
  50. {
  51.     code_page_table = select_cp_table(active_code_page = get_code_page());
  52. }
  53.  
  54. /*------------------------- read in an article -----------------------------*/
  55. TEXT *load_article(char *fnx, long offset)
  56. {
  57.     /*
  58.      *  Open the file and read it.  Save the author and organisation
  59.      *  fill in the structures
  60.      */
  61.  
  62.     FILE *tmp_file;
  63.     char buf[256], lnbuf[256], *p, *s, *token;
  64.     TEXT *tx;
  65.     LINE *ln, *lz;
  66.     int  ct, i;
  67.  
  68.     tx = NULL;
  69.     ct = 0;
  70.     current_char_set = DEFAULT_CHAR_SET;
  71.  
  72.     if ((tmp_file = flockopen(fnx, "rb")) != NULL) {
  73.  
  74.         fseek(tmp_file, offset, SEEK_SET);
  75.  
  76.         tx = xmalloc(sizeof(TEXT));
  77.         tx->top = NULL;
  78.         tx->start = NULL;
  79.         strcpy(tx->follow_up, "");
  80.         strcpy(tx->author, " ** none ** ");
  81.         strcpy(tx->organisation, " ** none ** ");
  82.  
  83.         while (fgets(buf, sizeof(buf)-1, tmp_file) != NULL) {
  84.  
  85.             if (strncmp(buf, "@@@@END", 7) == 0) break;
  86.  
  87.             expand_tabs(buf, sizeof(buf)-1);
  88.  
  89.             /*
  90.              *  We now have a line of input.  If the line is too long
  91.              *  it is wrapped at spaces or '!'.  The lines of text are
  92.              *  stored in LINE structures
  93.              */
  94.             p = &buf[0];
  95.             while (strlen(p) > 0) {
  96.  
  97.                 strcpy(lnbuf, p);
  98.                 if (strlen(p) <= 80) {
  99.                     strcpy(lnbuf, p);
  100.                     *p = '\x00';        /* signal we're ready for a new line */
  101.                 } else {
  102.                     /* can we split the line at a nice spot (space , !) ? */
  103.                     p += 79;
  104.                     for (i = 79; i > 50; i--) {
  105.                         if ((lnbuf[i] == ' ') || (lnbuf[i] == '!') ||
  106.                             (lnbuf[i] == ','))
  107.                             break;
  108.                         p--;
  109.                     }
  110.                     /* can't split nicely -- split at the end of the line */
  111.                     if (i <= 50) {
  112.                         p += (79-i);
  113.                         i = 79;
  114.                     }
  115.                     lnbuf[i] = '\x00';
  116.                 }
  117.  
  118.                 /* is it the first line - if so int the TEXT structure */
  119.                 if (ct == 0) {
  120.                     ln = xmalloc(sizeof(LINE));
  121.                     ln->last = NULL;
  122.                     tx->top = ln;
  123.                 } else {
  124.                     lz = ln;
  125.                     ln->next = xmalloc(sizeof(LINE));
  126.                     ln = ln->next;
  127.                     ln->last = lz;
  128.                 }
  129.  
  130.                 ln->index = ct;
  131.                 if (lnbuf[0] == '\n')    /* is the line empty? */
  132.                     ln->data = empty_line;    /* yes, save malloc() overhead */
  133.                 else {
  134.                     ln->data = xmalloc(strlen(lnbuf)+1);
  135.                     strcpy(ln->data, lnbuf);
  136.                 }
  137.  
  138.                 /* Find first line of body */
  139.                 if ((strlen(lnbuf) == 1) && (tx->start == NULL))
  140.                     tx->start = ln;
  141.  
  142.                 ct++;
  143.  
  144.                 /* save the header info */
  145.                 if ((tx->start == NULL) && (strnicmp("From:", lnbuf, 5) == 0)) {
  146.                     s = lnbuf + 5;
  147.                     while (*s && isspace(*s)) s++;
  148.                     *(s + WHO_LENGTH - 1) = '\0';
  149.                     strtok(strcpy(tx->author, s), "\n");
  150.                 }
  151.  
  152.                 if ((tx->start == NULL) &&  ((strnicmp("Organisation:", lnbuf, 13) == 0) || (strncmp("Organization:", lnbuf, 13) == 0))) {
  153.                     s = lnbuf + 13;
  154.                     while (*s && isspace(*s)) s++;
  155.                     *(s + ORG_LENGTH - 1) = '\0';
  156.                     strtok(strcpy(tx->organisation, s), "\n");
  157.                 }
  158.  
  159.                 if ((tx->start == NULL) && (strnicmp("Followup-To:", lnbuf, 12) == 0)) {
  160.                     s = lnbuf + 12;
  161.                     while (*s && isspace(*s)) s++;
  162.                     *(s + sizeof(tx->follow_up) - 1) = '\0';
  163.                     strtok(strcpy(tx->follow_up, s), "\n");
  164.                 }
  165.  
  166.                 if ((tx->start == NULL) && (strnicmp("Content-Type:", lnbuf, 13) == 0)) {
  167.                     s = lnbuf + 13;
  168.  
  169.                     while (*s && isspace(*s)) s++;    /* kill leading spaces */
  170.                     token = strtok(s, " ;\n");
  171.                     while (token != NULL) {
  172.                         if (strnicmp("charset=", token, 8) == 0) {
  173.                             current_char_set = select_char_set(token+8);
  174.                             break;
  175.                         }
  176.                         token = strtok(NULL, " ;\n");
  177.                     }
  178.                 }
  179.             }
  180.  
  181.         }
  182.  
  183.         ln->next = NULL;
  184.         tx->lines = ct;
  185.  
  186.         fclose(tmp_file);
  187.     }
  188.  
  189.     return(tx);
  190. }
  191.  
  192.  
  193.  
  194. /*---------------------- deallocate article memory ------------------------*/
  195. void free_article(TEXT *t)
  196. {
  197.  
  198.     LINE *l, *k;
  199.  
  200.     l = t->top;
  201.     while (l != NULL) {
  202.         k = l;
  203.         l = l->next;
  204.     if (k->data != empty_line)    /* don't free empty line pointer */
  205.             free(k->data);
  206.         free(k);
  207.     }
  208.  
  209.     free(t);
  210. }
  211.  
  212.  
  213.  
  214. /*---------------------------- read an article ----------------------------*/
  215. enum exit_codes read_article(ACTIVE *gp, TEXT *tx, char *subject, int a_ct, int of_ct)
  216. {
  217.     /*
  218.      *  This routine allows the user to read an article
  219.      */
  220.  
  221.     LINE   *this, *tmp;   /* current thread                    */
  222.     enum exit_codes exit_code;     /* why we are exiting the loop      */
  223.     char   sub_tmp[80];        /* new subject line */
  224.  
  225.     int    i, maxx;
  226.  
  227.     this = tx->start;
  228.     if (this->next != NULL)
  229.         this = this->next;            /* skip over blank line */
  230.     show_article(gp, tx, subject, this, a_ct, of_ct);
  231.  
  232.     exit_code = EX_CONT;
  233.     while ((exit_code == EX_CONT) || (exit_code == EX_DUMMY)) {
  234.  
  235.         exit_code = EX_CONT;
  236.         gotoxy(1,25);
  237.         switch (get_any_key()) {
  238.  
  239.                     case Fn1    :
  240.                     case '?'    :
  241.                     case 'h'    :
  242.                         show_help(HELP_ARTICLES);
  243.                         break;
  244.  
  245.                     case Fn2    :
  246.                         show_values();
  247.                         break;
  248.  
  249.                     case Fn3    :
  250.                         if (current_char_set++ == US_ASCII)
  251.                             current_char_set = 0;
  252.                         break;
  253.  
  254.                     case Fn4    :
  255.                         pipe_article(tx, my_stuff.hotpipe);
  256.                         message("-- Done --");
  257.                         break;
  258.  
  259.                     case UP_ARR :
  260.                         if (this->last != NULL) {
  261.                             this = this->last;
  262.                             gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  263.                             delline();
  264.                             gotoxy(1,TEXT_LINE);
  265.                             insline();
  266.                             clreol();
  267.                             cputs(translate_line(this->data, current_char_set));
  268.                             show_percent((int) ((100L * (this==NULL ? tx->lines+1 : min((this->index) + PAGE_LENGTH, tx->lines+1))) / ((tx->lines) + 1)));
  269.                         }
  270.                         exit_code = EX_DUMMY;
  271.                         break;
  272.  
  273.                     case DN_ARR :
  274.                         if (this->next != NULL &&
  275.                             (this->index + PAGE_LENGTH < tx->lines ||
  276.                              this->index <= tx->start->index)) {
  277.                             this = this->next;
  278.                             gotoxy(1,TEXT_LINE);
  279.